﻿using CaseManagerLibrary.Models;
using NetSDKCS;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CaseManagerLibrary.Socket
{
    public delegate void ReceivedEventHandler(string message, IPEndPoint remoteEp);

    public class TcpManager
    {
        private System.Net.Sockets.Socket socket;

        public event ReceivedEventHandler Received;

        private IPEndPoint localEp;
        private Thread socketThread;

        public event EventHandler Started;

        public TcpManager(IPEndPoint bindEp)
        {
            localEp = bindEp;
        }

        public void Start()
        {
            socketThread = new Thread(new ThreadStart(CreateSocket));
            socketThread.Start();
        }

        private void CreateSocket()
        {
            try
            {
                socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                socket.Bind(localEp);

                socket.Listen(0);

                Started?.Invoke(null, null);

                AcceptSocket();
            }
            catch (Exception ex)
            {
            }
        }

        private void AcceptSocket()
        {
            try
            {
                var temp = socket.Accept();

                System.IO.MemoryStream ms = new System.IO.MemoryStream();
                byte[] recvBytes = new byte[1024];

                int bytes = 0;// temp.Receive(recvBytes);
                while ((bytes = temp.Receive(recvBytes)) > 0)
                {
                    ms.Write(recvBytes, 0, bytes);
                    recvBytes = new byte[1024];
                }

                byte[] data = new byte[ms.Length];
                ms.Seek(0, System.IO.SeekOrigin.Begin);
                ms.Read(data, 0, data.Length);
                ms.Close();
                ms.Dispose();

                string recvStr = Encoding.UTF8.GetString(data);

                Received?.Invoke(recvStr, (temp.RemoteEndPoint as IPEndPoint));

                temp.Close();
            }
            catch (Exception ex)
            { }

            AcceptSocket();
        }

        public void Stop()
        {
            if (socket != null)
            {
                socket.Close();
                socket.Dispose();
            }
        }

        public HResult Send(IPEndPoint remoteEp, MessageBase msg)
        {
            string json = JsonConvert.SerializeObject(msg);

            return Send(remoteEp, json);
        }

        public HResult Send(IPEndPoint remoteEp, string data)
        {
            HResult result = new HResult();
            TcpClient client = new TcpClient();
            try
            {
                var outputBuffer = Encoding.UTF8.GetBytes(data);

                client.Connect(remoteEp);
                var ns = client.GetStream();
                ns.Write(outputBuffer, 0, outputBuffer.Length);
                ns.Close();

                result.success = true;
            }
            catch (Exception ex)
            {
                result.message = ex.Message + (ex.InnerException == null ? "" : ex.InnerException.Message);
                result.success = false;
            }
            finally
            {
                client.Close();
            }

            return result;
        }

        //public HResult SendFile(IPEndPoint remoteEp, FileStream fileStream)
        //{
        //    HResult result = new HResult();
        //    TcpClient client = new TcpClient();
        //    try
        //    {
        //        int read = 0;
        //        int total = Convert.ToInt32(fileStream.Length);
        //        int left = total;
        //        int buffLen = 0;
        //        byte[] outputBuffer = null;

        //        client.Connect(remoteEp);
        //        var ns = client.GetStream();
        //        fileStream.Seek(0, SeekOrigin.Begin);

        //        while (left > 0)
        //        {
        //            buffLen = left < 1024 * 1024 ? left : 1024 * 1024;

        //            outputBuffer = new byte[buffLen];

        //            read = fileStream.Read(outputBuffer, 0, buffLen);

        //            ns.Write(outputBuffer, 0, buffLen);

        //            left -= read;
        //        }

        //        ns.Close();

        //        result.success = true;
        //    }
        //    catch (Exception ex)
        //    {
        //        result.message = ex.Message + (ex.InnerException == null ? "" : ex.InnerException.Message);
        //        result.success = false;
        //    }
        //    finally
        //    {
        //        client.Close();
        //    }

        //    return result;
        //}
    }
}
